package com.free.semantic.core.concept.impl;

import com.free.semantic.common.*;
import com.free.semantic.core.ConceptInstanceManage;
import com.free.semantic.core.ConceptManage;
import com.free.semantic.core.RelationFunction;
import com.free.semantic.core.concept.BaseConcept;
import com.free.semantic.core.script.impl.ScriptEngineImpl;
import com.free.semantic.core.takeclient.ConceptInsTakeCommand;
import com.free.semantic.facade.Link;
import com.free.semantic.facade.Node;
import com.free.semantic.req.RelationDefine;
import com.free.semantic.utils.Utils;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static com.free.semantic.common.RangeObj.more;
import static com.free.semantic.common.RangeObj.one;
import static com.free.semantic.utils.Utils.*;

/**
 * 用语义网络的能力表达和管理自身
 */
public class ConceptSelfInfoConcept implements BaseConcept {

    /**
     * 关系定义
     */
    public static final String FIND_ONE = "find_one";

    public static final String FIND_MORE = "find_more";

    public static final String FIND_ONE_BY_2 = "find_one_by_more_one";

    public static final String FIND_ONE_BY_ONE_ONE = "find_one_by_one_one";


    public static final Set<String> relationLs = Ls.ofSet(FIND_ONE, FIND_MORE, FIND_ONE_BY_2, FIND_ONE_BY_ONE_ONE);


    /**
     * 概念定义
     */
    public static final String NODE = "node";

    public static final String LINK = "link";

    public static final String OBJECT = "object";

    public static final String RANGE_OBJECT = "rangeObject";

    public static final String RELATION = "relation";

    public static final String RELATION_DEF = "relationDefine";

    public static final String RELATION_INSTANCE = "relationInstance";

    public static final String HAS_IMPLEMENT = "hasImplement";

    public static final String POSSIBLE_RELATION_CHAIN = "possibleRelationChain";

    public static final String EXACTLY_RELATION_CHAIN = "exactlyRelationChain";

    public static final String RELATION_CHAIN = "relationChain";

    public static final String RANGE = "range";

    public static final String SOURCE = "source";

    public static final String DEST = "dest";

    public static final String ROOT_OBJECT = "rootObject";

    public static final String SEMANTIC_NET = "semanticNet";

    public static final String CHECK_MATCH = "checkMatch";

    public static final String SEMANTIC_VERSION = "theMaxSemanticVersion";

    public static final String CONCEPT_INS_TAKE_COMMAND = "conceptInsTakeCommand";

    /**
     * 动作定义
     */
    public static final String MERGE = "merge";

    public static final Set<String> keyConceptLs = Ls.ofSet(
            NODE, LINK, OBJECT, RANGE, RANGE_OBJECT, SOURCE, RELATION_DEF, RELATION_INSTANCE, POSSIBLE_RELATION_CHAIN,
            EXACTLY_RELATION_CHAIN, RELATION_CHAIN, CHECK_MATCH, DEST, ROOT_OBJECT, RELATION, HAS_IMPLEMENT,
            SEMANTIC_NET, SEMANTIC_VERSION, CONCEPT_INS_TAKE_COMMAND, MERGE);

    @Override
    public void initRelationDef(ConceptManage conceptManage) {
        addRelationDef(conceptManage, FIND_ONE, defineItem(oneObj("A"), oneObj("B")));
        addRelationDef(conceptManage, FIND_MORE, defineItem(oneObj("A"), moreObj("B")));
        addRelationDef(conceptManage, FIND_ONE_BY_2, defineItem(Ls.of(moreObj("A"), oneObj("B")), oneObj("C")));
        addRelationDef(conceptManage, FIND_ONE_BY_ONE_ONE, defineItem(Ls.of(oneObj("A"), oneObj("B")), oneObj("C")));


        createRelation(conceptManage, FIND_MORE, SEMANTIC_NET, NODE);
        createRelation(conceptManage, FIND_MORE, SEMANTIC_NET, LINK);

        createRelation(conceptManage, FIND_MORE, SEMANTIC_NET, RELATION_DEF);

        createRelation(conceptManage, FIND_MORE, SEMANTIC_NET, RELATION_INSTANCE);

        createRelation(conceptManage, FIND_ONE, SEMANTIC_NET, SEMANTIC_VERSION);

        createRelation(conceptManage, FIND_MORE, ROOT_OBJECT, OBJECT);

        createRelation2(conceptManage, FIND_MORE, OBJECT, RELATION);

        createRelation(conceptManage, FIND_ONE, RELATION, SOURCE);
        createRelation(conceptManage, FIND_ONE, RELATION, DEST);

        createRelation2(conceptManage, FIND_ONE_BY_2, SOURCE, DEST, HAS_IMPLEMENT);

        createRelation2(conceptManage, FIND_ONE_BY_2, SOURCE, DEST, POSSIBLE_RELATION_CHAIN);
        createRelation2(conceptManage, FIND_ONE_BY_2, SOURCE, DEST, EXACTLY_RELATION_CHAIN);

        createRelation2(conceptManage, FIND_MORE, POSSIBLE_RELATION_CHAIN, RELATION_CHAIN);
        createRelation2(conceptManage, FIND_ONE, EXACTLY_RELATION_CHAIN, RELATION_CHAIN);

        createRelation(conceptManage, FIND_MORE, SOURCE, RANGE_OBJECT);
        createRelation(conceptManage, FIND_ONE, DEST, RANGE_OBJECT);

        createRelation(conceptManage, FIND_ONE, RANGE_OBJECT, OBJECT);
        createRelation(conceptManage, FIND_ONE, RANGE_OBJECT, RANGE);

        createRelation2(conceptManage, FIND_ONE_BY_ONE_ONE, SEMANTIC_NET, CONCEPT_INS_TAKE_COMMAND, MERGE);

    }

    @Override
    public void initConcept(ConceptManage conceptManage) {
        for (String keyConceptL : keyConceptLs) {
            conceptManage.addConcept(keyConceptL);
        }
    }

    @Override
    public void initConceptImpl(ConceptInstanceManage instanceManage) {
        ConceptManage conceptManage = instanceManage.concept();

        instanceManage.registerFunction(Ls.of(SEMANTIC_NET), NODE, context -> {
            List<Node> allNode = conceptManage.getAllNode();
            context.setValue(NODE, allNode);
        });

        instanceManage.registerFunction(Ls.of(SEMANTIC_NET), LINK, context -> {
            List<Link> allNode = conceptManage.getAllLink();
            context.setValue(LINK, allNode);
        });

        instanceManage.registerFunction(Ls.of(SEMANTIC_NET), RELATION_DEF, context -> {
            List<RelationDefine> defines = conceptManage.getAllRelationDefine();
            context.setValue(RELATION_DEF, defines);
        });

        instanceManage.registerFunction(Ls.of(SEMANTIC_NET), RELATION_INSTANCE, context -> {
            List<RelationInstance> instance = conceptManage.getAllRelationInstance();
            context.setValue(RELATION_INSTANCE, instance);
        });

        instanceManage.registerFunction(Ls.of(SEMANTIC_NET), SEMANTIC_VERSION, context -> {
            int version = conceptManage.getLastVersion();
            context.setValue(SEMANTIC_VERSION, version);
        });

        instanceManage.registerFunction(Ls.of(ROOT_OBJECT), OBJECT, context -> {
            List<String> rootObjectList = conceptManage.findAllRootObjectList();
            context.setValue(OBJECT, rootObjectList);
        });

        instanceManage.registerFunction(Ls.of(OBJECT), RELATION, context -> {
            List<String> valueLs = context.getListValue(OBJECT);
            List<String> itemStr = new ArrayList<>();
            for (String value : valueLs) {
                List<RelationInstance> directRelationIns = conceptManage.getDirectRelationIns(value);
                for (RelationInstance directRelationIn : directRelationIns) {
                    List<RelationItem> items = directRelationIn.getRelationItems();
                    for (RelationItem item : items) {
                        itemStr.add(String.format("%s", item.toString()));
                    }
                }
            }
            context.setValue(RELATION, itemStr);
        });

        instanceManage.registerFunction(Ls.of(RELATION), SOURCE, context -> {
            List<String> valueLs = context.getListValue(RELATION);
            List<String> rangeObjLs = new ArrayList<>();
            for (String value : valueLs) {
                RelationItem relationItem = getRelationItem(value);
                List<RangeObj> objectList = relationItem.getSourceObjectList();
                for (RangeObj rangeObj : objectList) {
                    rangeObjLs.add(rangeObj.toString());
                }
            }
            context.setValue(SOURCE, rangeObjLs);
        });

        instanceManage.registerFunction(Ls.of(RELATION), DEST, context -> {
            List<String> valueLs = context.getListValue(RELATION);
            List<String> rangeObjLs = new ArrayList<>();
            for (String value : valueLs) {
                RelationItem relationItem = getRelationItem(value);
                rangeObjLs.add(relationItem.getDestObject().toString());
            }
            context.setValue(DEST, rangeObjLs);
        });

        registerTheSameFunction(instanceManage, SOURCE, RANGE_OBJECT);

        registerTheSameFunction(instanceManage, DEST, RANGE_OBJECT);

        instanceManage.registerFunction(Ls.of(RANGE_OBJECT), RANGE, context -> {
            List<String> valueLs = context.getListValue(RANGE_OBJECT);
            List<String> rangeLs = new ArrayList<>();
            for (String value : valueLs) {
                rangeLs.add(RangeObj.parse(value).getRange().toString());
            }
            context.setValue(RANGE, rangeLs);
        });

        instanceManage.registerFunction(Ls.of(RANGE_OBJECT), OBJECT, context -> {
            List<String> valueLs = context.getListValue(RANGE_OBJECT);
            List<String> rangeLs = new ArrayList<>();
            for (String value : valueLs) {
                rangeLs.add(RangeObj.parse(value).getObjectName());
            }
            context.setValue(OBJECT, rangeLs);
        });

        instanceManage.registerFunction(Ls.of(SOURCE, DEST), HAS_IMPLEMENT, context -> {
            List<String> source = context.getListValue(SOURCE);
            List<String> dest = context.getListValue(DEST);
            List<Boolean> hasImplement = new ArrayList<>();
            RelationFunction function = instanceManage.getFunction(source, dest.get(0));
            hasImplement.add(function != null);
            context.setValue(HAS_IMPLEMENT, hasImplement);
        });

        instanceManage.registerFunction(Ls.of(SOURCE, DEST), POSSIBLE_RELATION_CHAIN, context -> {
            List<String> source = context.getListValue(SOURCE);
            List<String> dest = context.getListValue(DEST);
            List<RelationChain> chainList = instanceManage.concept().findAllRelationChain(source, dest.get(0));
            context.setValue(POSSIBLE_RELATION_CHAIN, chainList);
        });

        instanceManage.registerFunction(Ls.of(more(SOURCE), one(DEST)), one(EXACTLY_RELATION_CHAIN), context -> {
            List<String> source = context.getListValue(SOURCE);
            List<String> dest = context.getListValue(DEST);
            List<RelationChain> chainList = instanceManage.concept().findExactRelationChain(source, dest.get(0));
            context.setValue(EXACTLY_RELATION_CHAIN, chainList);
        });

        registerTheSameFunction(instanceManage, Ls.of(POSSIBLE_RELATION_CHAIN), POSSIBLE_RELATION_CHAIN, RELATION_CHAIN);

        registerTheSameFunction(instanceManage, Ls.of(EXACTLY_RELATION_CHAIN), EXACTLY_RELATION_CHAIN, RELATION_CHAIN);

        instanceManage.registerFunction(Ls.of(SEMANTIC_NET, CONCEPT_INS_TAKE_COMMAND), MERGE, context -> {
            List<ConceptInsTakeCommand> source = context.getListValue(CONCEPT_INS_TAKE_COMMAND);
            ConceptInsTakeCommand conceptInsTakeCommand = source.get(0);
            ScriptEngineImpl scriptEngine = new ScriptEngineImpl();
            ConceptInstanceManage manageInsFromTake = scriptEngine.buildManageInsFromTake(conceptInsTakeCommand);
            Utils.mergerInstance(instanceManage, manageInsFromTake);
            context.setValue(MERGE, true);
        });
    }

    private static RelationItem getRelationItem(String str) {
        return RelationItem.parseFromStr(str);
    }

}
